home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / Libraries / VideoToolbox 94.11.17 / VideoToolboxSources / GetVoltage.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-09-05  |  12.3 KB  |  338 lines  |  [TEXT/KAHL]

  1. /*
  2. GetVoltage.c
  3. © 1990,1991,1992 Denis G. Pelli
  4. These subroutine are for measuring voltages via the Data Translation DT2211-PGL
  5. FORERUNNER analog NuBus card. The assumed unit-gain input range is VMIN to VMAX,
  6. e.g. 0 to 5 Volts. If you change this input range (by changing the jumpers on the card)
  7. then these defined constants should be changed appropriately. 
  8.  
  9. The on-board FIFO holds 1024 samples, so you can use InitiateVoltageSampling() to
  10. start the conversion, do something else, and come back later to collect the results,
  11. by calling RetrieveVoltages(). All the other routines are built upon these two.
  12.  
  13. BUGS:
  14. RetrieveVoltages() hangs up at high clock rates and high gains (e.g. 100 kHz at gain 1
  15. or 10 kHz at gain 500). This is almost certainly some sort of hardware problem.
  16. Perhaps Data Translation could advise a work-around. What happens is that
  17. we wait forever for the Control and Status Register to indicate that there is
  18. valid data. (It checks before getting each of the n samples.)
  19. Since the clock is presumably still running the data ought to appear
  20. eventually, even if the a/d can't quite keep up. Anyway, I can do all my work at
  21. 2 kHz or lower, so it's not an issue for me.***6/23/92 This problem now occurs
  22. even at 2 kHz, but it may be an interaction with the Radius Rocket.
  23.  
  24. I don't understand why, but the THINK C profiler timing data indicates that 
  25. RetrieveVoltages() is much too fast on the cases where a voltageOverflow occurs.
  26. The most likely explanation for this is some sort of glitch in the Profiler, probably
  27. an interaction with printf, so I'm ignoring it.
  28.  
  29. HISTORY:
  30. 8/8/89    dgp    written by denis,based on an early draft by Preeti
  31. 9/29/89 dgp    changed the #defines so that slot number appears in only one place.
  32. 3/28/90 dgp    call the new function CardSlot() that actually finds the ForeRunner card
  33.             on the NuBus if present, and fail gracefully if it's absent.
  34. 9/13/90    dgp    Added standard deviation to GetVoltage(). Tidied up the comments.
  35. 9/14/90    dgp    Broke up code into separate routines that initiate the sampling, and
  36.             later retrieve the samples.
  37.             Improved the error detection, handling, and reporting.
  38.             Made explicit and general the dependence on the unit-gain input voltage range.
  39.             Elaborated the main() test driver.
  40.             Sped up the key loop in RetrieveVoltages().
  41. 10/17/90 dgp removed unused variables from InitiateVoltageSampling() and
  42.             RetrieveVoltages().
  43. 5/21/91    dgp    GetVoltage() now automatically tries again at lower gain if there was
  44.             a voltage overflow. I also added the voltage limits to the diagnostic
  45.             messages.
  46. 8/24/91        dgp    Made compatible with THINK C 5.0.
  47. 6/22/92    dgp    added a brief pause between successive interrogations of the fifo when
  48.             fetching data, to prevent hang ups. I suspect that the problem
  49.             is that the fifo's input and output are not totally independent and the
  50.             excessively frequent interrogation of the output (waiting for the data
  51.             available flag to come up) prevented the fifo from accepting data.
  52. 6/23/92    dgp    well, the last fix helped but didn't solve the problem. I now explicitly
  53.             time out if the next data point doesn't appear after a reasonable wait
  54.             (100000 iterations). I modified the calling structure of GetVoltages and
  55.             RetrieveSamples to pass the number of samples by reference so that
  56.             when there is a buffer overflow or timeout the programs can proceed
  57.             using the reduced number of data actually retrieved.
  58. 10/23/92 dgp removed obsolete support for THINK C 4. Fine tuned RetrieveVoltages()
  59.             to make it as fast as possible. Removed all the beeps in the error
  60.             messages, because they annoyed me.
  61. 7/31/94    dgp changed frequency[] table from double to float, to save space.
  62. 9/5/94 dgp removed assumption in printf's that int==short.
  63. */
  64. #include "VideoToolbox.h"
  65. #include <math.h>
  66.  
  67. #define VMAX 5.0    /* unit-gain input range of a/d assumed to be VMIN to VMAX volts */
  68. #define VMIN 0.0
  69.  
  70. #define BASE_ADDR(slot)     (0xf0080000+(slot)*0x1100000)
  71. #define CS_REG         0x00
  72. #define    AD_DATA        0x10
  73. #define DAC_0_DATA    0x20
  74. #define DAC_1_DATA    0x30
  75. #define    DIO_COUNTER 0x40
  76. #define DIO_DATA    0x50
  77.  
  78. #define GAINS 4
  79. static double gain[GAINS]={1.,10.,100.,500.};
  80. #define FREQUENCIES 64
  81. static float frequency[FREQUENCIES]={
  82.     0.005,0.006,0.010,0.012,0.015,0.020,0.030,
  83.     0.050,0.060,0.060,0.100,0.120,0.150,0.200,0.300,
  84.     0.500,0.600,0.600,1.0,1.200,1.500,2.0,3.0,
  85.     5.0,6.0,6.0,10.0,12.0,15.0,20.0,30.0,
  86.     50.0,60.0,60.0,100.0,120.0,150.0,200.0,300.0,
  87.     500.0,600.0,600.0,1000.0,1200.0,1500.0,2000.0,3000.0,
  88.     5000.0,6000.0,6000.0,10000.0,12000.0,15000.0,20000.0,30000.0,
  89.     50000.0,60000.0,60000.0,100000.0,120000.0,150000.0,200000.0,300000.0,600000.0
  90. };
  91. static short frequencyCode[FREQUENCIES]={
  92.     63,15,55,47,39,31,23,62,14,7,54,46,38,30,22,
  93.     61,6,13,53,45,37,29,21,60,12,5,52,44,36,28,20,
  94.     59,11,4,51,43,35,27,19,58,3,10,50,42,34,26,18,
  95.     57,9,2,49,41,33,25,17,56,1,8,48,40,32,24,16,0
  96. };
  97.  
  98. #if 0
  99. #include <profile.h>
  100. void main(void);
  101.  
  102. void main()
  103. {
  104.     int i,k;
  105.     short channel=1;
  106.     long n=2000;
  107.     static double g=1.0,f=2000.,sd,voltDelta,voltZero,mean;
  108.     static unsigned short data[2000];
  109.     
  110.     Require(0);
  111.     for(i=0;i<3;i++)printf("%6.2f mV\n",1000.*VoltsDuringFrame(20));
  112.     InitProfile(200,3);
  113.     for(k=0;k<3;k++){
  114.         g=gain[k];
  115.         mean=GetVoltage(channel,&g,&f,n,&sd);
  116.         printf("n %ld,mean %f V,sd %f V,g %3.0f,f %.3f",n,mean,sd,g,f);
  117.         mean=GetVoltages(channel,&g,&f,n,data,&voltDelta,&voltZero);
  118.         printf(",range is %.3f to %.3f V\n",voltZero,voltDelta*4095+voltZero);
  119.         for(i=0;i<10;i++)printf("%5d",data[i]);
  120.         printf("\n");
  121.     }
  122. }
  123. #endif
  124.  
  125. double VoltsDuringFrame(double frames)
  126. /* sample channel 1 at 2 kHz for the specified number of 15 ms frames */
  127. {
  128.     double gain=10.;
  129.     double frequency=2000.;
  130.     long n;
  131.     short channel=1;
  132.     
  133.     n=(long)(0.5+frequency*0.015*frames);
  134.     return GetVoltage(channel,&gain,&frequency,n,NULL);
  135. }
  136.  
  137. double GetVoltage(short channel,double *gainPtr,double *frequencyPtr,long nDesired
  138.     ,double *sdPtr)
  139. /*
  140. Samples at specified rate, gain, and number of samples and returns the mean voltage.
  141. If sdPtr is not NULL, then the standard deviation is computed and returned in *sdPtr.
  142. */
  143. {
  144.     unsigned short *readingsPtr;
  145.     double voltDelta,voltZero,v;
  146.     int error,i;
  147.     register unsigned long sum,m;
  148.     register double sumSquares;
  149.     long n;
  150.     
  151. tryAgain:
  152.     if(nDesired >= 1L<<20){
  153.         printf("GetVoltage: n %ld too large\n",nDesired);
  154.         return NAN;
  155.     }
  156.     readingsPtr=(unsigned short *)NewPtr(nDesired*sizeof(unsigned short));
  157.     if(readingsPtr==NULL){
  158.         printf("GetVoltage: out of memory!\n");
  159.         return NAN;
  160.     }
  161.     n=nDesired;
  162.     error=GetVoltages(channel,gainPtr,frequencyPtr,&n,readingsPtr,&voltDelta,&voltZero);
  163.     if(error & voltageBufferOverflow){
  164.         printf("GetVoltage: Warning: retrieved only %4ld of the %4ld samples requested.\n",n,nDesired);
  165.     }
  166.     if(error & voltageOverflow){
  167.         if(*gainPtr>gain[0]){
  168.             printf("GetVoltage: voltageOverflow >%.2f V at gain %.0f. "
  169.                 "Trying again at lower gain.\n",VMAX/(*gainPtr),*gainPtr);
  170.             *gainPtr /=10.0;
  171.             goto tryAgain;
  172.         }
  173.         else printf("GetVoltage: voltageOverflow >%.2f V at gain %.0f.\n"
  174.             ,VMAX/(*gainPtr),*gainPtr);
  175.     }
  176.     if(error & voltageUnderflow)printf("GetVoltage: voltageUnderflow <%.3f V.\n"
  177.         ,VMIN/(*gainPtr));
  178.     sum=0;
  179.     for(i=0;i<n;i++) sum+=readingsPtr[i];
  180.     v=(double)sum/(double)n;
  181.     if(sdPtr!=NULL){
  182.         sumSquares=0.0;
  183.         for(i=0;i<n;i++){
  184.             m=readingsPtr[i];
  185.             sumSquares+=m*m;
  186.         }
  187.         *sdPtr=voltDelta*sqrt((sumSquares-n*v*v)/(n-1));
  188.     }
  189.     DisposPtr((Ptr)readingsPtr);
  190.     return voltDelta*v+voltZero;
  191. }
  192.  
  193. short GetVoltages(short channel,double *gainPtr,double *frequencyPtr,long *nPtr
  194.     ,unsigned short readings[],double *voltDeltaPtr,double *voltZeroPtr)
  195. /*
  196. Retrieves *nPtr samples from the a/d. The samples are placed in the array
  197. readings[]. The returned value of *voltDeltaPtr, when multiplied by the samples,
  198. will yield volts. The function uses a/d gain and frequency settings as close as
  199. possible to those requested, and sets the parameters to the values actually
  200. used. The returned value will be 0 when the operation was successful, and
  201. nonzero if there was an error. The error value is the OR of those that occured:
  202. voltageBufferOverflow, voltageUnderflow, voltageOverflow. In case of buffer
  203. overflow the value of *nPtr will be reduced to the number of good samples.
  204. */
  205. {
  206.     int error=0;
  207.     
  208.     error |= InitiateVoltageSampling(channel,gainPtr,frequencyPtr,voltDeltaPtr,voltZeroPtr);
  209.     error |= RetrieveVoltages(nPtr,readings);
  210.     return error;
  211. }
  212.  
  213.  
  214. short InitiateVoltageSampling(short channel,double *gainPtr,double *frequencyPtr
  215.     ,double *voltDeltaPtr,double *voltZeroPtr)
  216. /*
  217. Initiates sampling by the a/d at specified gain and frequency (in Hz). The
  218. samples accumulate in the FIFO, which will hold 1024 before overflowing. Each
  219. sample multiplied by *voltDeltaPtr and added to *voltZeroPtr is the input
  220. voltage. This function will use gain and frequency settings as close as possible
  221. to those requested, and then set the parameters to the values actually used. The
  222. returned value is always 0.
  223. */
  224. {
  225.     register volatile short *Con_Stat_Reg;
  226.     unsigned volatile short *AD_Data_Reg;
  227.     unsigned volatile short *DIO_Counter_Reg;
  228.     register short i;
  229.     short mode;
  230.     short iGain,iFrequency;
  231.     static int slot;
  232.     
  233.     slot=ForeRunnerSlot();            /* NuBus slot of ForeRunner card */
  234.     if(slot<0){
  235.         PrintfExit("InitiateVoltageSampling: Sorry, I need a Data Translation ForeRunner A/D card.\n");
  236.     }
  237.  
  238.     AD_Data_Reg = (unsigned short *)(AD_DATA+BASE_ADDR(slot));
  239.     Con_Stat_Reg = (short *)(CS_REG+BASE_ADDR(slot));
  240.     DIO_Counter_Reg = (unsigned short *)(DIO_COUNTER+BASE_ADDR(slot));
  241.  
  242.     /* find nearest gain */
  243.     for(i=0;i<GAINS-1;i++) if(*gainPtr <= (gain[i]+gain[i+1])/2.0) break;
  244.     iGain=i;
  245.     *gainPtr=gain[iGain];
  246.     *voltDeltaPtr=(VMAX-VMIN)/4095.0/gain[iGain];
  247.     *voltZeroPtr=VMIN/gain[iGain];
  248.     
  249.     /* find nearest frequency */
  250.     for(i=0;i<FREQUENCIES-1;i++)
  251.         if(*frequencyPtr <= (frequency[i]+frequency[i+1])/2.0) break;
  252.     iFrequency=i;
  253.     *frequencyPtr=frequency[iFrequency];
  254.     
  255.     /* This follows the steps suggested in the FORERUNNER manual pages:192,194,195. */
  256.     *Con_Stat_Reg = (iGain<<6)+channel;                /* mode zero: stop */
  257.     *DIO_Counter_Reg=0;                                /* stop the clock */
  258.     while(*Con_Stat_Reg<0) i=*AD_Data_Reg;            /* empty the FIFO */
  259.     *DIO_Counter_Reg=frequencyCode[iFrequency];        /* set clock frequency */
  260.     mode=1;                                            /* enable */
  261.     *Con_Stat_Reg=(1<<12)+(mode<<8)+(iGain<<6)+channel; /* clear a/d error flag */
  262.     *AD_Data_Reg=0;                                    /* start */
  263.     return 0;
  264. }
  265.  
  266. short RetrieveVoltages(long *nPtr,unsigned short readings[])
  267. /*
  268. Retrieves *nPtr samples from the a/d. The samples are placed in the array
  269. readings[]. The returned value will be 0 when the operation was successful, and
  270. nonzero if there was an error. The error value is the OR of those that occured:
  271. voltageBufferOverflow, voltageUnderflow, voltageOverflow. In case of buffer 
  272. overflow the value of *nPtr will be reduced to the number of good samples.
  273. */
  274. {
  275.     register volatile short *Con_Stat_Reg;
  276.     register volatile unsigned short *AD_Data_Reg;
  277.     register unsigned short *readingsPtr;
  278.     register long i,j,nDesired=*nPtr;
  279.     int slot;                        /* NuBus slot of ForeRunner card */
  280.     int error=0;
  281.     register unsigned short r;
  282.     
  283.     slot=ForeRunnerSlot();
  284.     if(slot<0){
  285.         PrintfExit("RetrieveVoltages: Sorry, I need a Data Translation ForeRunner A/D card.\n");
  286.     }
  287.  
  288.     AD_Data_Reg = (unsigned short *)(AD_DATA+BASE_ADDR(slot));
  289.     Con_Stat_Reg = (short *)(CS_REG+BASE_ADDR(slot));
  290.  
  291.     /* retrieve data as quickly as possible, before the FIFO overflows */
  292.     readingsPtr=&readings[0];
  293.     for(i=0;i<nDesired;i++) {
  294.         j=100000;
  295.         while(*Con_Stat_Reg>=0) if(--j==0)goto timeout;
  296.         *readingsPtr++ = *AD_Data_Reg;
  297.     }
  298.     if(0){
  299.     timeout:
  300. //        printf("RetrieveVoltages timed out waiting for %ld-th datum of %ld. ",i,nDesired);
  301. //        printf("*Con_Stat_Reg == 0x%X\n",*Con_Stat_Reg);
  302.         *nPtr=i;                                    /* use only the valid data */
  303.         for(;i<nDesired;i++)*readingsPtr++=0;
  304.         error|=voltageBufferOverflow;
  305.     }
  306.     *Con_Stat_Reg &= ~(3<<8);                         /* disable conversions */
  307.  
  308.     /* if we want more than the FIFO can hold, then check for FIFO overflow */
  309.     r=*Con_Stat_Reg;                // force THINK C to read a word, not a byte
  310.     if(*nPtr>1024 && r & 1<<11){
  311.         error|=voltageBufferOverflow;
  312.         *nPtr=1024;                                    /* use only the valid data */
  313.     }
  314.     while(*Con_Stat_Reg<0)i=*AD_Data_Reg;            /* now empty the FIFO */
  315.     
  316.     /* check for voltage out of range */
  317.     for(i=0;i<*nPtr;i++){
  318.         r=readings[i];
  319.         if(r==0)error|=voltageUnderflow;
  320.         if(r==4095)error|=voltageOverflow;
  321.     }
  322.     return error;
  323. }
  324.  
  325. int ForeRunnerSlot(void)
  326. /* caches the slot number to speed up subsequent calls */
  327. {
  328.     static gotIt=0;
  329.     static slot=-1;
  330.     
  331.     if(!gotIt) {
  332.         slot=CardSlot(".ForeRunner");
  333.         gotIt=1;
  334.     }
  335.     return slot;
  336. }
  337.  
  338.